package com.wjy.icu.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;

import com.wjy.icu.common.CacheManage;
import com.wjy.icu.common.constant.SmsResponse;
import com.wjy.icu.common.enums.SystemSMSEnum;
import com.wjy.icu.common.exception.BusinessException;
import com.wjy.icu.domain.SmsRecord;
import com.wjy.icu.mapper.SmsRecordMapper;
import com.wjy.icu.service.ISmsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class SmsServiceImpl implements ISmsService {

    @Autowired
    CacheManage cacheManage;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    SmsRecordMapper smsRecordMapper;

    @Value("${sms.accessKeyId}")
    private String accessKeyId;

    @Value("${sms.accessSecret}")
    private String accessSecret;

    @Value("${sms.signName}")
    private String signName;

    @Value("${sms.accessKeyIdtb}")
    private String accessKeyIdtb;

    @Value("${sms.accessSecrettb}")
    private String accessSecrettb;

    @Value("${sms.signNametb}")
    private String signNametb;

    @Value("${sms.templateCodeRegister}")
    private String templateCodeRegister;    //注册
    @Value("${sms.templateCodeCheck}")
    private String templateCodeCheck;       //身份验证
    @Value("${sms.templateCodeLogin}")
    private String templateCodeLogin;       //登录确认
    @Value("${sms.templateCodeResetPassword}")
    private String templateCodeResetPassword;    //修改密码
    @Value("${sms.templateCodeUpdateUser}")
    private String templateCodeUpdateUser;        //信息变更
    @Value("${sms.templateCodeRemoteLogin}")
    private String templateCodeRemoteLogin;       //登录异常
    @Value("${sms.templateCodeOrderReminder}")
    private String templateCodeOrderReminder;       //订单医生提醒
    @Value("${sms.templateCodeUserOrderReminder}")
    private String templateCodeUserOrderReminder;       //订单用户提醒
    @Value("${sms.templateCodeDoctorApplySuccessReminder}")
    private String templateCodeDoctorApplySuccessReminder;       //审核通过提醒
    @Value("${sms.templateCodeDoctorApplyFailReminder}")
    private String templateCodeDoctorApplyFailReminder;       //审核未通过提醒


    @Override
    public boolean sendSms(String iponeNUmber,int type,boolean isSendCode) {
        if(StringUtils.isBlank(iponeNUmber)) {
            log.info("参数错误");
            throw new BusinessException("参数错误");
        }
        //发短信接口幂等性操作验证
        if(stringRedisTemplate.hasKey("redis_sms_user_token" + iponeNUmber)) {
            throw new BusinessException("验证码发送频繁");
        }
        Boolean send = false;
        send = lock(iponeNUmber, type, isSendCode);
        return send;

    }
    public synchronized boolean lock(String iponeNUmber,int type,boolean isSendCode){
        //设置短信接口幂等性校验redis key
        stringRedisTemplate.opsForValue().set("redis_sms_user_token"+iponeNUmber, DateUtil.currentSeconds()+"",60 , TimeUnit.SECONDS);
        //设置key 自动 +1
        Long count = stringRedisTemplate.boundValueOps("redis_sms_user" + iponeNUmber).increment(1);
        if (count==1){
            //设置 30 分钟过期
            stringRedisTemplate.expire("redis_sms_user"+iponeNUmber, 30*60 , TimeUnit.SECONDS);
            stringRedisTemplate.opsForValue().set("redis_sms_user_time"+iponeNUmber, DateUtil.currentSeconds()+"");
        }else {
            //判断上次时间间隔是否超过1分钟
            if(stringRedisTemplate.hasKey("redis_sms_user_time" + iponeNUmber)) {
                String s = stringRedisTemplate.opsForValue().get("redis_sms_user_time" + iponeNUmber);
                DateTime date = DateUtil.date(Long.parseLong(s)*1000);
                if (DateUtil.between(new Date(), date, DateUnit.SECOND) > 60) {
                    log.info("重新设置最新发送时间");
                    stringRedisTemplate.opsForValue().set("redis_sms_user_time" + iponeNUmber, DateUtil.currentSeconds() + "");
                } else {
                    log.info("验证码发送频繁");
                    throw new BusinessException("验证码发送频繁");
                }
            }
        }
        if(count > 5){
            log.info("验证码发送频繁,超过了限定的次数");
            throw new BusinessException("验证码发送频繁,超过了限定的次数");
        }
        boolean send = send(iponeNUmber, type, isSendCode);
        //删除redis短信接口幂等性校验redis key
        stringRedisTemplate.delete("redis_sms_user_token" + iponeNUmber);
        return send;
    }

    private boolean send(String iponeNUmber, int type, boolean isSendCode){
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret);
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
        request.putQueryParameter("RegionId", "cn-hangzhou");
        request.putQueryParameter("PhoneNumbers", iponeNUmber);
        switch (SystemSMSEnum.getByCode(type) ){
            case REGISTER:
                request.putQueryParameter("TemplateCode", templateCodeRegister);
                break;
            case CHECK:
                request.putQueryParameter("TemplateCode", templateCodeCheck);
                break;
            case LOGIN:
                request.putQueryParameter("TemplateCode", templateCodeLogin);
                break;
            case ResetPassword:
                request.putQueryParameter("TemplateCode", templateCodeResetPassword);
                break;
            case UpdateUser:
                request.putQueryParameter("TemplateCode", templateCodeUpdateUser);
                break;
            case RemoteLogin:
                request.putQueryParameter("TemplateCode", templateCodeRemoteLogin);
                break;
            case OrderReminder:
                request.putQueryParameter("TemplateCode", templateCodeOrderReminder);
                break;
            case UserOrderReminder:
                request.putQueryParameter("TemplateCode", templateCodeUserOrderReminder);
                break;
            case DoctorApplySuccessReminder:
                request.putQueryParameter("TemplateCode", templateCodeDoctorApplySuccessReminder);
                break;
            case DoctorApplyFailReminder:
                request.putQueryParameter("TemplateCode", templateCodeDoctorApplyFailReminder);
                break;
            default:
                break;
        }
        request.putQueryParameter("SignName", signName);
        JSONObject object=new JSONObject();
        String randCode=getRandCode(6);
        if (isSendCode){
            log.info("验证码为：{}",randCode);
            object.put("code",randCode);
        }
        request.putQueryParameter("TemplateParam", object.toJSONString());
        try {
            CommonResponse response = client.getCommonResponse(request);
            log.info(response.getData());
            SmsResponse smsResponse = JSONObject.parseObject(response.getData(), SmsResponse.class);
            if (!smsResponse.getMessage().equalsIgnoreCase("ok")){
                return false;
            }
            log.info("存储验证码到redis");
            setCode(iponeNUmber+"_"+type,randCode);
            //记录短信发送记录 
            saveSms( iponeNUmber, type,randCode);
            return true;
        } catch (Exception e) {
            log.error("{}",e);
            return false;
        }
    }

    private void saveSms(String iponeNUmber, int type, String randCode) {
        SmsRecord record = new SmsRecord();
        record.setCode(randCode);
        record.setGmtCreate(LocalDateTime.now());
        record.setPhone(iponeNUmber);
        record.setType(type);
        smsRecordMapper.insertSelective(record);
    }


    @Override
    public boolean sendSmstb(String iponeNUmber, int type, boolean isSendCode) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyIdtb, accessSecrettb);
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
        request.putQueryParameter("RegionId", "cn-hangzhou");
        request.putQueryParameter("PhoneNumbers", iponeNUmber);
        switch (SystemSMSEnum.getByCode(type) ){
            case REGISTER:
                request.putQueryParameter("TemplateCode", templateCodeRegister);
                break;
            case CHECK:
                request.putQueryParameter("TemplateCode", templateCodeCheck);
                break;
            case LOGIN:
                request.putQueryParameter("TemplateCode", templateCodeLogin);
                break;
            case ResetPassword:
                request.putQueryParameter("TemplateCode", templateCodeResetPassword);
                break;
            case UpdateUser:
                request.putQueryParameter("TemplateCode", templateCodeUpdateUser);
                break;
            case RemoteLogin:
                request.putQueryParameter("TemplateCode", templateCodeRemoteLogin);
                break;
            case OrderReminder:
                request.putQueryParameter("TemplateCode", templateCodeOrderReminder);
                break;
            case UserOrderReminder:
                request.putQueryParameter("TemplateCode", templateCodeUserOrderReminder);
                break;
            case DoctorApplySuccessReminder:
                request.putQueryParameter("TemplateCode", templateCodeDoctorApplySuccessReminder);
                break;
            case DoctorApplyFailReminder:
                request.putQueryParameter("TemplateCode", templateCodeDoctorApplyFailReminder);
                break;
            default:
                break;
        }
        request.putQueryParameter("SignName", signNametb);
        JSONObject object=new JSONObject();
        String randCode=getRandCode(4);
        if (isSendCode){
            log.info("验证码为：{}",randCode);
            object.put("code",randCode);
        }
        request.putQueryParameter("TemplateParam", object.toJSONString());
        try {
            CommonResponse response = client.getCommonResponse(request);
            log.info(response.getData());
            SmsResponse smsResponse = JSONObject.parseObject(response.getData(), SmsResponse.class);
            if (!smsResponse.getMessage().equalsIgnoreCase("ok")){
                return false;
            }
            log.info("存储验证码到redis");
            setCode(iponeNUmber+"_"+type,randCode);
            //记录短信发送记录
            saveSms( iponeNUmber, type,randCode);
            return true;
        } catch (Exception e) {
            log.error("{}",e);
            return false;
        }
    }

    @Override
    public boolean sendSms(String iponeNUmber,int type,String submittime) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret);
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
        request.putQueryParameter("RegionId", "cn-hangzhou");
        request.putQueryParameter("PhoneNumbers", iponeNUmber);
        switch (SystemSMSEnum.getByCode(type) ){
            case REGISTER:
                request.putQueryParameter("TemplateCode", templateCodeRegister);
                break;
            case CHECK:
                request.putQueryParameter("TemplateCode", templateCodeCheck);
                break;
            case LOGIN:
                request.putQueryParameter("TemplateCode", templateCodeLogin);
                break;
            case ResetPassword:
                request.putQueryParameter("TemplateCode", templateCodeResetPassword);
                break;
            case UpdateUser:
                request.putQueryParameter("TemplateCode", templateCodeUpdateUser);
                break;
            case RemoteLogin:
                request.putQueryParameter("TemplateCode", templateCodeRemoteLogin);
                break;
            case OrderReminder:
                request.putQueryParameter("TemplateCode", templateCodeOrderReminder);
                break;
            case UserOrderReminder:
                request.putQueryParameter("TemplateCode", templateCodeUserOrderReminder);
                break;
            case DoctorApplySuccessReminder:
                request.putQueryParameter("TemplateCode", templateCodeDoctorApplySuccessReminder);
                break;
            case DoctorApplyFailReminder:
                request.putQueryParameter("TemplateCode", templateCodeDoctorApplyFailReminder);
                break;
            default:
                break;
        }
        request.putQueryParameter("SignName", signName);
       request.putQueryParameter("TemplateParam", "{\"submittime\":\""+submittime+"\"}");
        try {
            CommonResponse response = client.getCommonResponse(request);
            log.info(response.getData());
            SmsResponse smsResponse = JSONObject.parseObject(response.getData(), SmsResponse.class);
            if (!smsResponse.getMessage().equalsIgnoreCase("ok")){
                return false;
            }else {
            }
            return true;
        } catch (Exception e) {
            log.error("{}",e);
            return false;
        }
    }

    @Override
    public void verify(String iponeNUmber, int type, String code) {
        if (cacheManage.isExist(iponeNUmber+"_"+type)){
            log.info("手机验证码未失效");
            log.info(cacheManage.get(iponeNUmber+"_"+type));
            String s = (String) cacheManage.get(iponeNUmber+"_"+type);
            if (!code.equalsIgnoreCase(s)){
                throw new BusinessException("手机验证码错误");
            }else {
                //正确后将验证码删除掉，防止重复使用
                cacheManage.remove(iponeNUmber+"_"+type);
            }
        }else {
            throw new BusinessException("手机验证码失效");
        }
    }

    @Override
    public void verifytb(String iponeNUmber, int type, String code) {
        if (cacheManage.isExist(iponeNUmber+"_"+type)){
            log.info("手机验证码未失效");
            log.info(cacheManage.get(iponeNUmber+"_"+type));
            String s = (String) cacheManage.get(iponeNUmber+"_"+type);
            if (!code.equalsIgnoreCase(s)){
                throw new BusinessException("手机验证码错误");
            }else {
                //正确后将验证码删除掉，防止重复使用
                cacheManage.remove(iponeNUmber+"_"+type);
            }
        }else {
            throw new BusinessException("手机验证码失效");
        }

    }

    /**
     * 生成随机验证码
     * @param digits
     * @return
     */
    public static String getRandCode(int digits) {
        StringBuilder sBuilder = new StringBuilder();
        Random rd = new Random((new Date()).getTime());

        for(int i = 0; i < digits; ++i) {
            sBuilder.append(String.valueOf(rd.nextInt(9)));
        }

        return sBuilder.toString();
    }
    private  void setCode(String phoneNumber,String code) throws Exception{
        
        log.info("存储手机验证码");
        cacheManage.set(phoneNumber,code,(long)300000);
    }
    private  String getCode(String phoneNumber) throws Exception{
        if (cacheManage.isExist(phoneNumber)){
            log.info("手机验证码未失效");
            log.info(cacheManage.get(phoneNumber));
            return cacheManage.get(phoneNumber);
        }else {
            throw new Exception("手机验证码失效");
        }
    }
}
